package com.zhihuishu.micro.course.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.lang3.ArrayUtils;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import com.google.common.collect.Lists;
import com.zhihuishu.micro.course.dao.LabelMapper;
import com.zhihuishu.micro.course.dto.CategoryDto;
import com.zhihuishu.micro.course.dto.CourseCategoryDto;
import com.zhihuishu.micro.course.helper.ArrayHelper;
import com.zhihuishu.micro.course.model.CourseLabel;
import com.zhihuishu.micro.course.model.Label;
import com.zhihuishu.micro.course.service.CategoryService;
import com.zhihuishu.toolkit.jedis.JedisHelper;

/**
 * <pre>
 * 课程分类，使用Redis缓存，缓存Key设计
 *              category:#id                            单个分类
 *              category:#id:children           子分类列表
 * </pre>
 * 
 * @author zhanglikun
 * @date 2015年10月21日 下午6:20:23
 */
@Service("categoryService")
public class CategoryServiceImpl extends BaseService implements CategoryService {

    @Resource
    private LabelMapper labelMapper;

    @Resource(name = "redisTemplate")
    private RedisTemplate<String, CategoryDto> categoryDtoRedisTemplate;

    @Resource(name = "redisTemplate")
    private RedisTemplate<String, Integer> integerRedisTemplate;

    /** 课程分类缓存前缀 */
    private static final String CATEGORY_CACHE_KEY_PREFIX = "category";

    @Override
    public CategoryDto get(int categoryId) {
        categoryDtoRedisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<CategoryDto>(
                CategoryDto.class));
        BoundValueOperations<String, CategoryDto> bvoHandler = categoryDtoRedisTemplate
                .boundValueOps(JedisHelper.key(CATEGORY_CACHE_KEY_PREFIX, categoryId));
        // 从Redis中[category:#categoryId]读取CategoryDto对象
        CategoryDto category = bvoHandler.get();
        if (category == null) {
            // 从数据库中查询
            category = this.toCategoryDto(labelMapper.get(categoryId));
            // 非空则加入到缓存
            if (category != null)
                bvoHandler.set(category);
        }
        return category;
    }

    @Override
    public List<CategoryDto> list(int parentId) {
        // 从Redis中读取ID列表[category:#categoryId:children]
        integerRedisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<Integer>(Integer.class));
        BoundSetOperations<String, Integer> bsoHandler = integerRedisTemplate.boundSetOps(JedisHelper.key(
                CATEGORY_CACHE_KEY_PREFIX, parentId, "children"));
        // 从缓存中获取子分类ID合集
        Set<Integer> categoryIds = bsoHandler.members();
        if (CollectionUtils.isEmpty(categoryIds)) {
            // 从数据库中查询子分类ID集合
            Integer[] labelIds = labelMapper.list(parentId);
            // 查询列表空，自然无需再放缓存，直接返回之
            if (ArrayUtils.isEmpty(labelIds))
                return null;
            // 将列表加入到缓存
            bsoHandler.add(labelIds);
            // 赋值子分类ID集合
            categoryIds = ArrayHelper.toSet(labelIds);
        }
        return _list(categoryIds);
    }

    /**
     * 根据分类ID合集获取分类列表
     * 
     * @param categoryIds
     * @return
     */
    private List<CategoryDto> _list(Set<Integer> categoryIds) {
        if (CollectionUtils.isEmpty(categoryIds))
            return null;
        // 遍历分类ID列表，组装缓存Key集合
        List<String> keys = new ArrayList<String>();
        for (Integer categoryId : categoryIds) {
            keys.add(JedisHelper.key(CATEGORY_CACHE_KEY_PREFIX, categoryId));
        }
        // 从缓存中取出实际分类信息
        categoryDtoRedisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<CategoryDto>(
                CategoryDto.class));
        // 由于即使未命中，也不再处理，所以需要保证缓存中一定存在全部的分类信息
        return categoryDtoRedisTemplate.opsForValue().multiGet(keys);
    }

    /**
     * Model转换为DTO(字段名不一致)
     * 
     * @param label
     * @return
     */
    private CategoryDto toCategoryDto(Label label) {
        if (label == null)
            return null;
        CategoryDto c = new CategoryDto();
        c.setCategoryId(label.getLabelId());
        c.setContent(label.getLabelContent());
        c.setLevel(label.getLabelLevel());
        c.setParentId(label.getParentId());
        return c;
    }

    @Override
    public List<CourseCategoryDto> listByCourse(long courseId) {
        List<CourseLabel> list = labelMapper.listByCourse(courseId);
        if (CollectionUtils.isEmpty(list))
            return null;
        List<CourseCategoryDto> target = new ArrayList<CourseCategoryDto>();
        for (CourseLabel cl : list) {
            CourseCategoryDto ccd = new CourseCategoryDto();
            ccd.setId(cl.getId());
            ccd.setFirstId(cl.getFlabelId());
            ccd.setFirst(this.get(cl.getFlabelId()));
            ccd.setSecondId(cl.getSlabelId());
            ccd.setSecond(this.get(cl.getSlabelId()));
            ccd.setThirdId(cl.getTlabelId());
            ccd.setThird(this.get(cl.getTlabelId()));
            ccd.setCourseId(cl.getCourseId());
            target.add(ccd);
        }
        return target;
    }

    @Override
    public List<CourseCategoryDto> listByCourse(List<Long> courseIds) {
        List<CourseLabel> list=labelMapper.listByCourseIds(courseIds);
        List<CourseCategoryDto> target = new ArrayList<CourseCategoryDto>();
        for (CourseLabel cl : list) {
            CourseCategoryDto ccd = new CourseCategoryDto();
            ccd.setId(cl.getId());
            ccd.setFirstId(cl.getFlabelId());
            ccd.setFirst(this.get(cl.getFlabelId()));
            ccd.setSecondId(cl.getSlabelId());
            ccd.setSecond(this.get(cl.getSlabelId()));
            ccd.setThirdId(cl.getTlabelId());
            ccd.setThird(this.get(cl.getTlabelId()));
            target.add(ccd);
        }
        return target;
    }

    @Override
    public Integer saveCourseCategory(CourseCategoryDto courseCategory) {
        Assert.notNull(courseCategory);
        CourseLabel cl = new CourseLabel();
        cl.setCourseId(courseCategory.getCourseId());
        cl.setFlabelId(courseCategory.getFirstId());
        cl.setSlabelId(courseCategory.getSecondId());
        cl.setTlabelId(courseCategory.getThirdId());
        labelMapper.saveCourseLabel(cl);
        return cl.getId();
    }

    @Override
    public void updateCourseCategory(CourseCategoryDto courseCategory) {
        Assert.notNull(courseCategory);
        Assert.notNull(courseCategory.getId());
        CourseLabel cl = new CourseLabel();
        cl.setId(courseCategory.getId());
        cl.setCourseId(courseCategory.getCourseId());
        cl.setFlabelId(courseCategory.getFirstId());
        cl.setSlabelId(courseCategory.getSecondId());
        cl.setTlabelId(courseCategory.getThirdId());
        labelMapper.updateCourseLabel(cl);
    }

    @Override
    public void saveCCCategory(CourseCategoryDto courseCategory) {
        StringBuilder categoryIds = new StringBuilder(20);
        categoryIds.append(courseCategory.getFirstId()).append(",").append(courseCategory.getSecondId())
                .append(",").append(courseCategory.getThirdId());
        List<Integer> categoryIdList = new ArrayList<Integer>(20);
        categoryIdList.add(courseCategory.getFirstId());
        categoryIdList.add(courseCategory.getSecondId());
        categoryIdList.add(courseCategory.getThirdId());
        List<String> courseLable = labelMapper.findCourseLabelByIds(categoryIdList);
        StringBuilder categoryString = new StringBuilder(50);
        for (String string : courseLable) {
            categoryString.append(string).append(",");
        }
        labelMapper.updatCCCourseLable(courseCategory.getCourseId(), categoryIds.toString(),
                categoryString.substring(0, categoryString.length() - 1));

    }

    @Override
    public void updateCCCategory(long courseId) {
        StringBuilder courseLableIds = new StringBuilder(100);
        StringBuilder courseLableContent = new StringBuilder();
        List<CourseLabel> courseLabels = labelMapper.listByCourse(courseId);
        List<Integer> tempList = null;
        for (CourseLabel courseLabel : courseLabels) {
            tempList = new ArrayList<Integer>(3);
            tempList.add(courseLabel.getFlabelId());
            tempList.add(courseLabel.getSlabelId());
            tempList.add(courseLabel.getTlabelId());
            List<String> courseLable = labelMapper.findCourseLabelByIds(tempList);
            for (String string : courseLable) {
                courseLableContent.append(string).append(",");
            }
            courseLableIds.append(courseLabel.getFlabelId()).append(",");
            courseLableIds.append(courseLabel.getSlabelId()).append(",");
            courseLableIds.append(courseLabel.getTlabelId()).append(",");
            courseLableIds.append("||");
        }
        labelMapper.updatCCCourseLable(courseId, courseLableIds.substring(0, courseLableIds.length() - 2),
                courseLableContent.substring(0, courseLableContent.length() - 1));

    }

    @Override
    public void deleteById(Integer id) {
        labelMapper.deleteByPrimaryKey(id);

    }

    @Override
    public List<CategoryDto> listAllLables() {
        List<Label> labels=labelMapper.listAllLables();
        if (log.isDebugEnabled()) {
            log.debug("查询到的课程分类基础信息为{}",labels);
        }
       
        List<CategoryDto> categoryDtos=Lists.newArrayListWithCapacity(labels.size());
        for (Label label : labels) {
            categoryDtos.add(toCategoryDto(label));
            
        }
        return categoryDtos;
    }

}
